/************************************************************************************
* PlaylistWidget.cpp                                                                *
*                                                                                   *
* Copyright (C) 2011 Varuna L Amachi                                                *
*                                                                                   *
* This program is free software; you can redistribute it and/or modify              *
* it under the terms of the GNU General Public License as published by              *
* the Free Software Foundation; either version 2 of the License, or any             *
* later version.                                                                    *
*                                                                                   *
* This program is distributed in the hope that it will be useful, but               *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY        *
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for       *
* more details. You should have received a copy of the GNU General Public           *
* License along with this program; if not, write to the Free Software Foundation,   *
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                       *
*                                                                                   *
*************************************************************************************/


#include <QGridLayout>
#include <QLabel>
#include <QFileDialog>
#include <QDesktopServices>
#include <QAction>
#include <QToolButton>
#include <QMenu>
#include <QPushButton>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QList>
#include <QUrl>
#include <QPalette>
#include <QProgressBar>
#include <QHeaderView>
#include <QScrollBar>


#include "PlaylistWidget.h"
#include "common/SizeConstants.h"
#include "common/Utils.h"
#include "common/Constants.h"


PlaylistWidget::PlaylistWidget(QWidget *parent) :
    QWidget(parent) {
    m_playlist = new PlaylistModel(this);
//    m_view = new QTableView();
    m_view = new QTreeView(this);
    m_toolBar = new QToolBar(this);
    m_loader = new FileSystemMediaLoader(this);
    m_progress = new QProgressBar(this);
    m_status = new QLabel(this);
    m_action = ACTION_NONE;

    connect(m_playlist, SIGNAL(selected(MediaItem*,int)),
            this, SLOT(indexChanged(MediaItem*, int)));
    connect(m_playlist, SIGNAL(playlistChanged()), this, SLOT(setActionValidity()));
    connect(m_playlist, SIGNAL(repeatConfigChanged(LoopType,LoopType)), this, SLOT(setActionValidity()));
    connect(m_playlist, SIGNAL(randomConfigChanged(bool)), this, SLOT(setActionValidity()));
    connect(m_view, SIGNAL(clicked(QModelIndex)), this, SLOT(setActionValidity()));
    connect(m_loader, SIGNAL(loaded(MediaItem*)), this, SLOT(itemLoaded(MediaItem*)));
    connect(m_loader, SIGNAL(finishedLoading(QList<MediaItem*>*)),
            this, SLOT(loadingFinished()));
    connect(m_loader, SIGNAL(loadingStarted(int)), this, SLOT(loadingStarted(int)));
    connect(m_loader, SIGNAL(progress(int, QString)), m_progress, SLOT(setValue(int)));
    setupUi();
    setupToolbar();
    setAcceptDrops(true);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}


PlaylistModel* PlaylistWidget::model() {
    return m_playlist;
}

QTreeView *PlaylistWidget::view() {
    return m_view;
}




void PlaylistWidget::setupUi() {
    this->setAutoFillBackground(true);
    m_toolBar->setAutoFillBackground(true);

    m_view->setWordWrap(false);
    m_view->setAlternatingRowColors(true);
    m_view->setAutoScroll(true);
    m_view->setSortingEnabled(true);
    m_view->setRootIsDecorated(false);
    m_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
    m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_view->setFocusPolicy(Qt::WheelFocus);
    m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_view->setModel(m_playlist);
    m_view->setFont(QFont(m_view->font().defaultFamily(), 9));
    m_view->header()->setResizeMode(0, QHeaderView::Stretch);
    m_view->setColumnWidth(1, 16);
    m_view->header()->setStretchLastSection(false);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(m_view);
    mainLayout->addWidget(m_toolBar, 0, Qt::AlignCenter);

    m_status->setMinimumWidth(FIRST_SPLITTER_WIDTH / 2);
    m_status->setMinimumWidth(FIRST_SPLITTER_WIDTH / 2);
    m_progress->setMinimumWidth(FIRST_SPLITTER_WIDTH /2);
    m_progress->setMaximumWidth(FIRST_SPLITTER_WIDTH /2);
    QHBoxLayout* statusLayot  = new QHBoxLayout();
    statusLayot->addWidget(m_status);
    statusLayot->addWidget(m_progress);
    mainLayout->addLayout(statusLayot);
    m_progress->hide();
    clearStatus();
    setLayout(mainLayout);
}



void PlaylistWidget::indexChanged(MediaItem* , int index) {
    m_view->clearSelection();
//    m_view->selectRow(index);
    selectRow(index);
}


void PlaylistWidget::setupToolbar() {
    m_toolBar->setContentsMargins(10,0,10,0);

    m_addFolderAction = new QAction(QIcon(":/add_folder"), tr("Append Folder"), m_toolBar); //<<Set>>
    m_addFolderAction->setShortcut(tr("Shift+Ctrl+A"));
    connect(m_addFolderAction, SIGNAL(triggered()), this, SLOT(addFolder()));
    m_toolBar->addAction(m_addFolderAction);

    m_addFilesAction  = new QAction(QIcon(":/add_files"), tr("Insert Files"), m_toolBar);
    m_addFilesAction ->setShortcut(tr("Shift+Ctrl+S"));
    connect(m_addFilesAction  , SIGNAL(triggered()), this, SLOT(addFiles()));
    m_toolBar->addAction(m_addFilesAction);

    QAction* insertAction = new QAction(QIcon(":/insert_as_current"), tr("Inser File As Current"), m_toolBar);
    insertAction->setShortcut(tr("Shift+Ctrl+D"));
    connect(insertAction , SIGNAL(triggered()), this, SLOT(insertFile()));
    m_toolBar->addAction(insertAction);

    m_toolBar->addSeparator();

    m_removeAction = new QAction(QIcon(":/remove_selected"), tr("Remove"), this) ;
    m_removeAction->setShortcut(QKeySequence::Delete);
    connect(m_removeAction , SIGNAL(triggered()), this, SLOT(removeItems()));
    m_toolBar->addAction(m_removeAction);
    m_removeAction->setEnabled(false);

    m_removeAllAction = new QAction(QIcon(":/clear_playlist"), "Clear Playlist", this);
    m_removeAllAction->setShortcut(tr("Shift+Ctrl+X"));
    connect(m_removeAllAction, SIGNAL(triggered()), this, SLOT(clearPlaylist()));
    m_toolBar->addAction(m_removeAllAction);

    m_toolBar->addSeparator();

    m_moveUp = new QAction(QIcon(":/move_up"), tr("Move Track Up"), m_toolBar);
    m_moveUp->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Up));
    connect(m_moveUp, SIGNAL(triggered()), this, SLOT(moveUp()));
    m_toolBar->addAction(m_moveUp);

    m_moveDown = new QAction(QIcon(":/move_down"), tr("Move Track Down"), m_toolBar);
    m_moveDown->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Down));
    connect(m_moveDown, SIGNAL(triggered()), this, SLOT(moveDown()));
    m_toolBar->addAction(m_moveDown);

    m_toolBar->addSeparator();

    m_randomize = new QAction(QIcon(":/sequential"), tr("Progression : Sequential"), m_toolBar);
    m_randomize->setShortcut(tr("Shift+Ctrl+R"));
    connect(m_randomize, SIGNAL(triggered()), this, SLOT(randomValueChanged()));
    m_toolBar->addAction(m_randomize);

    m_loopAction = new QAction(QIcon(":/repeat_all"), tr("Repeat All"), this);
    m_loopAction->setShortcut(tr("Shift+Ctrl+L"));
    connect(m_loopAction, SIGNAL(triggered()), this, SLOT(loopValueChanged()));
    m_toolBar->addAction(m_loopAction);

    m_moveUp->setEnabled(false);
    m_moveDown->setEnabled(false);
}


void PlaylistWidget::addFolder() {
    QString dirName = QFileDialog::getExistingDirectory(this, "Add Folder",
                            QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
    if(! dirName.isEmpty()) {
        QList<QUrl>* urls = new QList<QUrl>();
        urls->append(QUrl::fromLocalFile(dirName));
        setCurrentAction(ACTION_APPEND);
        m_loader->load(urls);
    }
}


void PlaylistWidget::addUrls(QList<QUrl> qurls) {
    if(! qurls.isEmpty()) {
        QList<QUrl>* urls = new QList<QUrl>(qurls);
        setCurrentAction(ACTION_APPEND);
        m_loader->load(urls);
    }
}


void PlaylistWidget::addFiles() {
    QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"),
              QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
    if(! files.empty()) {
        QList<QUrl>* urls = new QList<QUrl>();
        foreach(QString fileName, files) {
            urls->append(QUrl::fromLocalFile(fileName));
        }
        setCurrentAction(ACTION_APPEND);
        m_loader->load(urls);
    }
}


void PlaylistWidget::insertFile() {
    QString file = QFileDialog::getOpenFileName(this, tr("Select Music Files"),
                        QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
    if(file.length() != 0) {
        QList<QUrl>* urls = new QList<QUrl>();
        urls->append(QUrl::fromLocalFile(file));
        setCurrentAction(ACTION_INSERT_AS_CURRENT);
        m_loader->load(urls);
    }
}


void PlaylistWidget::dragEnterEvent(QDragEnterEvent * event) {
    if(event->mimeData()->hasFormat("text/uri-list")) {
        event->acceptProposedAction();
    }
}


void PlaylistWidget::dropEvent(QDropEvent *event) {
    QList<QUrl>* urls = new QList<QUrl>();
    urls->append(event->mimeData()->urls());
    setCurrentAction(ACTION_APPEND);
    m_loader->load(urls);
}




void PlaylistWidget::removeItems() {
    QModelIndexList indices = m_view->selectionModel()->selectedRows();
    QList<int> list;
    if(! indices.empty()) {
        foreach(QModelIndex index, indices) {
            list.append(index.row());
        }
        m_playlist->removeItems(list);
    }
}


void PlaylistWidget::moveUp() {
    QItemSelectionModel* selection = m_view->selectionModel();
    if(selection != NULL) {
        QModelIndex index = selection->selectedRows().at(0);
        m_playlist->moveUp(index.row());
//        m_view->selectRow(index.row() - 1); //this is a hack
        selectRow(index.row() - 1);
        m_view->scrollTo(selection->selectedRows().at(0));
    }
}


void PlaylistWidget::moveDown() {
    QItemSelectionModel* selection = m_view->selectionModel();
    if(selection != NULL) {
        QModelIndex index = selection->selectedRows().at(0);
        m_playlist->moveDown(index.row());
//        m_view->selectRow(index.row() + 1);
        selectRow(index.row() + 1);
        m_view->scrollTo(selection->selectedRows().at(0));
    }
}





void PlaylistWidget::clearPlaylist() {
    m_playlist->clear();
    m_removeAction->setEnabled(false);
    m_moveUp->setEnabled(false);
    m_moveDown->setEnabled(false);
}



void PlaylistWidget::randomValueChanged() {
    m_playlist->setRandom( !m_playlist->isRandom()); //flip't
    m_randomize->setIcon(QIcon(m_playlist->isRandom()?":/shuffle":":/sequential"));
    m_randomize->setText(QString("Progression : ")+(m_playlist->isRandom()?"Random":"Sequential"));
}


void PlaylistWidget::loopValueChanged() {
    switch(m_playlist->repeat()) {
    case NoRepeat   : m_playlist->setRepeat(RepeatAll);
                      m_loopAction->setText(tr("Repeat All"));
                      m_loopAction->setIcon(QIcon(":/repeat_all"));
                      break;
    case RepeatAll  : m_playlist->setRepeat(RepeatCurrent);
                      m_loopAction->setIcon(QIcon(":/repeat_one"));
                      m_loopAction->setText(tr("Repeat Current"));
                      break;
    default         : m_playlist->setRepeat(NoRepeat);
                      m_loopAction->setIcon(QIcon(":/no_repeat"));
                      m_loopAction->setText(tr("No Repeat"));
                      break;
    }
}


void PlaylistWidget::setActionValidity() {
    QItemSelectionModel* model = m_view->selectionModel();
    if(model != NULL) {
        int numSelection = model->selectedRows().size();
        m_removeAction->setEnabled(numSelection);

        bool moveEnabled = (numSelection == 1 &&
                           model->selectedRows().at(0).row() != 0);
        m_moveUp->setEnabled(moveEnabled);

        moveEnabled = (numSelection == 1 &&
                        static_cast<quint32>(model->selectedRows().at(0).row()) != m_playlist->numItems() - 1);
        m_moveDown->setEnabled(moveEnabled);
    }

}


void PlaylistWidget::itemLoaded(MediaItem *item) {
        if(m_action == ACTION_APPEND) {
            m_playlist->append(item, m_playlist->numItems()?false:true);
        }
        else if( m_action == ACTION_INSERT){
            int targetRow = m_view->selectionModel()->selectedRows().at(0).row();
            if(targetRow < 0) {
                targetRow = m_playlist->numItems();
            }
            if(static_cast<quint32>(targetRow) < m_playlist->numItems()) {
                m_playlist->insert(targetRow, item, m_playlist->numItems()?false:true);
            }
            else {
                m_playlist->append(item, m_playlist->numItems()?false:true);
            }
        }
        else if(m_action == ACTION_INSERT_AS_CURRENT) {
            m_playlist->insertAsCurrent(item);
        }
        else {
            //with all due respect sir, you're not supposed to be here..
        }
//        m_action = ACTION_NONE;
}


void PlaylistWidget::loadingFinished() {
    m_progress->setVisible(false);
    m_loader->clear();
    m_action = ACTION_NONE;
    clearStatus();
}


void PlaylistWidget::loadingStarted(int numFilesToLoad) {
    m_progress->setVisible(true);
    setStatus(tr("Loading..."));
    m_progress->setMaximum(numFilesToLoad);
}


void PlaylistWidget::setStatus(QString text) {
    m_status->setText(text);
    m_status->setVisible(true);
}


void PlaylistWidget::clearStatus() {
    m_status->hide();
}


void PlaylistWidget::setCurrentAction(PlaylistWidget::CurrentAction action) {
    if(m_action == ACTION_NONE) {
        m_action = action;
    }
}


void PlaylistWidget::contextMenuEvent(QContextMenuEvent *event) {
    QMenu menu(this);
    menu.addAction(m_addFolderAction);
    menu.addAction(m_addFilesAction);
    menu.addAction(m_removeAction);
    menu.addAction(m_removeAllAction);
    menu.exec(event->globalPos());
}



void PlaylistWidget::selectRow(int index) {
    QItemSelectionModel *selection = m_view->selectionModel();
    selection->select (
        QItemSelection (
            m_view->model ()->index (index, 0),
            m_view->model ()->index (index, m_view->model ()->columnCount () - 1)),
        QItemSelectionModel::Select);
    m_view->scrollTo(m_view->model ()->index (index, 0));
}
